(function (fruit, util, ui, dom, viewEngine) {
    ui.define('fruit.ui.DataTable', {
        events:['ItemMouseEnter', 'ItemMouseLeave'],
        view:{
            tag:'table',
            props:{
                'class':'f-table f-table-sample',
                style:'width:100%'
            },
            content:[
                {
                    tag:'colgroup',
                    name:'columnsContainer',
                    template:{
                        tag:'col'
                    }
                },
                {
                    tag:'thead',
                    content:{
                        name:'headersContainer',
                        tag:'tr',
                        template:{
                            tag:'th'
                        }
                    }
                },
                {
                    name:'itemsContainer',
                    tag:'tbody',
                    template:{
                        tag:'tr'
                    }
                }
            ]
        },
        properties:{
            template:{
                observable:true
            },
            columns:{
                observable:true
            },
            items:{
                getter:function () {
                    return this._items;
                },
                setter:function (value) {
                    this._items = value;
                    if (value instanceof fruit.ui.CollectionView) {
                        this._dataView = value;
                    }
                    else {
                        this._dataView = new fruit.ui.CollectionView(value);
                    }

                    this._dataView.on('collectionChanged', this._onCollectionChanged, this);
                    this.notifyPropertyChanged('items');
                    this.selectedItem(null);
                    this._generateItems();
                }
            },
            selectionMode:{
                getter:function () {
                    return this._selectionMode;
                },
                setter:function (value) {
                    this._selectionMode = value;
                    this.notifyPropertyChanged('selectionMode');
                    this.notifyPropertyChanged('columns');
                }
            },
            selectedItem:{
                value:null,
                observable:true
            },
            selectedItems:{
                observable:true
            }
        },
        methods:{
            onInit:function () {
                this.inherited();
                this._selectionMode = 'none';

                this.on('propertyChanged', function (sender, event) {
                    var prop = event.property;
                    if (prop === 'columns') {
                        this.notifyPropertyChanged('template');
                        this._generateHeaders();
                    }
                    else if (prop === 'template') {
                        var template = this.template();
                        if (!template) {
                            template = {
                                tag:'tr',
                                content:[]
                            };

                            if (this._selectionMode !== 'none') {
                                template.content.push({
                                    tag:'td',
                                    content:{
                                        type:'fruit.ui.CheckBox',
                                        props:{
                                            checked:'{#selected}'
                                        }
                                    }
                                });
                            }

                            util.each(this.columns(), function (column) {
                                template.content.push({
                                    tag:'td',
                                    content:column.template || '{' + column.path + '}'
                                });
                            });
                        }
                        this._template = template;
                        this._generateItems();
                    }
                });
            },
            _generateHeaders:function () {
                var columns = this.columns();
                var columnsContainer = this.$('columnsContainer');
                var headersContainer = this.$('headersContainer');
                var colEl;

                columnsContainer.empty();
                headersContainer.empty();

                if (this._selectionMode === 'multiple') {
                    colEl = viewEngine.create({
                        tag:'col'
                    });
                    columnsContainer.appendChild(colEl);

                    var thEl = viewEngine.create({
                        tag:'th',
                        content:{
                            type:'fruit.ui.CheckBox'
                        }
                    });

                    thEl.on('change', this._onHeaderChange, this);
                    var selectedItems = this.selectedItems();
                    if (selectedItems) {
                        selectedItems.on('collectionChanged', function () {
                            thEl.firstChild().checked(selectedItems.length() == this.items().length());
                        }, this);
                    }
                    headersContainer.appendChild(thEl);
                }
                else if (this._selectionMode === 'single') {
                    colEl = viewEngine.create({
                        tag:'col'
                    });
                    columnsContainer.appendChild(colEl);

                    var thEl = viewEngine.create({
                        tag:'th'
                    });

                    headersContainer.appendChild(thEl);
                }

                util.forEach(columns, function (col) {
                    colEl = viewEngine.create({
                        tag:'col'
                    });
                    if (col.width) {
                        colEl.setStyle('width', col.width);
                    }
                    columnsContainer.appendChild(colEl);

                    var thEl = viewEngine.create({
                        tag:'th'
                    });

                    thEl.set('text', col.text || col.path || '');
                    thEl.on('click', this._onHeaderClick, this);
                    thEl._sortKey = col.sortingPath || col.path;
                    thEl._sortAsNumber = col.sortAsNumber || false;

                    headersContainer.appendChild(thEl);
                }, this);
            },
            _generateItems:function () {
                var template = this._template;
                var itemsContainer = this.$('itemsContainer');
                var itemsContainerId = itemsContainer.$id;
                var items = this._dataView;
                var selectionMode = this._selectionMode;
                var selectedItems = this.selectedItems();
                var itemEl;

                itemsContainer.empty();

                if (template && items) {
                    var Row = this._Row = ui.define({
                        view:template,
                        properties:{
                            selected:{
                                value:false,
                                observable:true
                            }
                        }
                    });

                    util.forEach(items, function (item) {
                        itemEl = new Row();
                        itemEl.clearBinding('model');
                        itemEl.model(item);
                        item['__bindingEl' + itemsContainerId] = itemEl._element;
                        if (selectionMode == 'multiple') {
                            itemEl.listen('selected', function (sender, event) {
                                if (selectedItems) {
                                    if (event.newValue) {
                                        selectedItems.add(item);
                                    }
                                    else {
                                        selectedItems.remove(item);
                                    }
                                }
                            }, this);
                        }
                        else if (selectionMode == 'single') {
                            itemEl.listen('selected', function (sender, event) {
                                if (event.newValue) {
                                    itemsContainer.children(function (child) {
                                        if (child !== sender) {
                                            child.selected(false);
                                        }
                                    });
                                    this.selectedItem(item);
                                }
                                else {
                                    this.selectedItem(null);
                                }
                            }, this);
                        }

                        itemsContainer.appendChild(itemEl);

                        itemEl.on('mouseenter', function () {
                            this.fire('ItemMouseEnter', itemEl);
                        }, this);

                        itemEl.on('mouseleave', function () {
                            this.fire('ItemMouseLeave', itemEl);
                        }, this);
                    }, this);
                }
            },
            _onCollectionChanged:function (sender, event) {
                var container = this.$('itemsContainer');
                var containerId = container.$id;
                var containerEl = container._element;
                var action = event.action;
                var item = event.item;
                var selectedItems = this.selectedItems();
                var selectionMode = this._selectionMode;
                if (action == 'add') {
                    var itemEl = new this._Row();
                    itemEl.model(item);
                    item['__bindingEl' + containerId] = itemEl._element;

                    if (selectionMode == 'multiple') {
                        itemEl.listen('selected', function (sender, event) {
                            if (selectedItems) {
                                if (event.newValue) {
                                    selectedItems.add(item);
                                }
                                else {
                                    selectedItems.remove(item);
                                }
                            }
                        }, this);
                    }
                    else if (selectionMode == 'single') {
                        itemEl.listen('selected', function (sender, event) {
                            if (event.newValue) {
                                container.children(function (child) {
                                    if (child !== sender) {
                                        child.selected(false);
                                    }
                                });
                                this.selectedItem(item);
                            }
                            else {
                                this.selectedItem(null);
                            }
                        }, this);
                    }

                    dom.insertAt(containerEl, itemEl._element, event.index);

                    itemEl.on('mouseenter', function () {
                        this.fire('ItemMouseEnter', itemEl);
                    }, this);

                    itemEl.on('mouseleave', function () {
                        this.fire('ItemMouseLeave', itemEl);
                    }, this);
                }
                else if (action == 'remove') {
                    dom.removeChild(containerEl, item['__bindingEl' + containerId]);
                    if (selectedItems) {
                        selectedItems.remove(item);
                    }
                }
                else if (action == 'sort') {
                    this._dataView.forEach(function (item) {
                        dom.appendChild(containerEl, item['__bindingEl' + containerId]);
                    });
                }
                else if (action == 'reset') {
                    dom.empty(containerEl);
                    this._dataView.forEach(function (item) {
                        dom.appendChild(containerEl, item['__bindingEl' + containerId]);
                    });
                }
            },
            _onHeaderChange:function (sender, event) {
                var checked = sender.firstChild().checked();
                this.$('itemsContainer').children(function (item) {
                    item.selected(checked);
                });
            },
            _onHeaderClick:function (sender, event) {
                if (sender._sortKey) {
                    var des = sender._sortDes;
                    this.$('headersContainer').children(function (header) {
                        header.removeClass('asc');
                        header.removeClass('desc');
                        header._sortDes = false;
                    });

                    if (des) {
                        sender.removeClass('asc');
                        sender.addClass('desc');
                    }
                    else {
                        sender.removeClass('desc');
                        sender.addClass('asc');
                    }

                    this._dataView.sort(sender._sortKey, des, sender._sortAsNumber);
                    sender._sortDes = !des;
                }
            }
        }
    });
})(fruit, fruit.util, fruit.ui, fruit.dom, fruit.ui.viewEngine);
